﻿using LS.DicomViewer.Common;
using LS.Screening.UI.Common;
using ReactiveUI.Fody.Helpers;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace LS.DicomViewer.ViewModels
{
    public class DicomViewModel : ViewModel
    {
        #region 属性/变量

        /// <summary>
        /// 提示信息
        /// </summary>
        [Reactive]
        public string NotifyMessage { get; set; }

        /// <summary>
        /// 影像地址
        /// </summary>
        [Reactive]
        public string DicomFilePath { get; set; }

        /// <summary>
        /// 是否播放中
        /// </summary>
        [Reactive]
        public bool Playing { get; set; } = false;

        /// <summary>
        /// 像素比
        /// </summary>
        [Reactive]
        public double PixelRate { get; set; } = 1;

        /// <summary>
        /// 位图
        /// </summary>
        [Reactive]
        public BitmapSource ImageSource { get; set; }

        /// <summary>
        /// 是否显示操作工具栏
        /// </summary>
        [Reactive]
        public bool ShowDrawToolbar { get; set; } = true;

        /// <summary>
        /// 是否显示播放工具栏
        /// </summary>
        [Reactive]
        public bool ShowPlayToolbar { get; set; } = true;

        /// <summary>
        /// 是否显示播放工具栏
        /// </summary>
        [Reactive]
        public bool Show3DButton { get; set; } = true;

        /// <summary>
        /// Dicom文件最大帧序号
        /// </summary>
        [Reactive]
        public int MaxFrameIndex { get; set; }

        /// <summary>
        /// Dicom信息
        /// </summary>
        [Reactive]
        public DicomInfo CurrentDicom { get; set; }

        /// <summary>
        /// SOPInstanceUID
        /// </summary>
        [Reactive]
        public string SOPInstanceUID { get; set; } = string.Empty;

        /// <summary>
        /// 当前浏览帧序号
        /// </summary>
        [Reactive]
        public int CurrentFrameIndex { get; set; } = -1;

        /// <summary>
        /// 缩放率
        /// </summary>
        [Reactive]
        public float Scale { get; set; } = 1;

        /// <summary>
        /// 是否显示绘图点数据
        /// </summary>
        [Reactive]
        public bool ShowDrawPoints { get; set; } = true;

        #endregion 属性/变量

        /// <summary>
        /// 重置
        /// </summary>
        public DelegateCommand ResetCommand { get; set; }

        /// <summary>
        /// 滚动鼠标显示下一张
        /// </summary>
        public DelegateCommand<int?> NextCommand { get; set; }

        /// <summary>
        /// 放大/缩水
        /// </summary>
        public DelegateCommand<float?> ScaleCommand { get; set; }

        public DelegateCommand PlayCommand { get; set; }

        public DelegateCommand StopCommand => new DelegateCommand(() => Playing = false);

        private System.Threading.CancellationTokenSource tokenSource = new System.Threading.CancellationTokenSource();
        /// <summary>
        /// 当前Dicom文件播放帧序号发生变化时
        /// </summary>
        public Action<int?> CurrentFrameIndexChanging { get; set; }
        /// <summary>
        /// 当前Dicom文件播放帧序号发生变化
        /// </summary>
        public Action<int?> CurrentFrameIndexChanged { get; set; }

        public DicomViewModel()
        {
            NextCommand = new DelegateCommand<int?>((a) => ToNext(a));
            PlayCommand = new DelegateCommand(Play);
        }

        #region 方法

        public override void OnPropertyChanging(string propertyName, object oldValue, object newValue)
        {
            base.OnPropertyChanging(propertyName, oldValue, newValue);
            if (propertyName == nameof(CurrentFrameIndex))
            {
                CurrentFrameIndexChanging?.Invoke((int?)oldValue);
            }
        }

        public override void OnPropertyChanged(string propertyName, object oldValue, object newValue)
        {
            base.OnPropertyChanged(propertyName, oldValue, newValue);
            if (propertyName == nameof(CurrentFrameIndex))
            {
                CurrentFrameIndexChanged?.Invoke((int?)newValue);
                ShowImage();
            }
            if (propertyName == nameof(CurrentDicom))
            {
                NotifyPropertyChanged(nameof(ShowPlayToolbar));
                NotifyPropertyChanged(nameof(Show3DButton));
            }
        }

        #region 加载图片

        /// <summary>
        /// 从路径中加载影像文件
        /// </summary>
        /// <param name="path"></param>
        public async Task Load(string path)
        {
            Reset();
            CurrentDicom = null;
            DicomFilePath = path;
            if (!File.Exists(DicomFilePath)) return;
            IsBusy = true;
            try
            {
                NotifyMessage = "正在加载Dicom文件，请稍候...";
                CurrentDicom = await DicomViewerHelper.SaveToCache(DicomFilePath, null, null);//227
                MaxFrameIndex = CurrentDicom.NumberOfFrames - 1;
                CurrentFrameIndex = 0;
                ShowImage();
            }
            catch (Exception ex)
            {
                MessageBox.Show("打开Dicom文件出错，请检查文件是否损坏！" + Environment.NewLine + ex.GetInnerMessage(), "系统提示");
                throw;
            }
            finally
            {
                NotifyMessage = string.Empty;
                GC.Collect();
                IsBusy = false;
            }
        }

        System.Threading.CancellationTokenSource stopToken = new System.Threading.CancellationTokenSource();

        public void Reset()
        {
            Scale = 1;
            Playing = false;
            CurrentFrameIndex = 0;
            stopToken.Cancel();
        }

        private void Play()
        {
            if (Playing) return;
            Playing = true;
            stopToken = new System.Threading.CancellationTokenSource();
            Task.Run(async () =>
            {
                while (Playing && CurrentDicom != null)
                {
                    ToNext();
                    await Task.Delay(1000 / CurrentDicom.DisplayFrameRate);
                }
            }, stopToken.Token);
        }

        public void Clear()
        {
            Playing = false;
            CurrentDicom = null;
            ImageSource = null;
            CurrentFrameIndex = -1;
            GC.Collect();
        }

        /// <summary>
        /// 显示下一张图片
        /// </summary>
        /// <param name="step"></param>
        private void ToNext(int? step = 1)
        {
            if (CurrentDicom == null) return;
            var index = CurrentFrameIndex + step.Value;

            if (index >= CurrentDicom.NumberOfFrames)
            {
                CurrentFrameIndex = 0;
            }
            else if (index < 0)
            {
                CurrentFrameIndex = CurrentDicom.NumberOfFrames - 1;
            }
            else
            {
                CurrentFrameIndex = index;
            }
        }

        /// <summary>
        /// 显示下一张图片,给定索引与当前索引相等时不作处理
        /// </summary>
        /// <param name="index"></param>
        public void SetCurrentFrameIndex(int index)
        {
            if (CurrentDicom == null || index >= CurrentDicom.NumberOfFrames || index < 0) return;
            if (CurrentFrameIndex == index) return;
            CurrentFrameIndex = index;
            ShowImage();
        }

        private void ShowImage()
        {
            if (CurrentDicom == null) return;
            if (CurrentFrameIndex < 0)
            {
                ImageSource = null;
                return;
            }
            try
            {
                Dispatcher.BeginInvoke(() => ImageSource = CurrentDicom.GetImageSource(CurrentFrameIndex));
            }
            catch { }
        }

        /// <summary>
        /// 将指定帧图片保存到指定文件
        /// </summary>
        /// <param name="index"></param>
        /// <param name="path"></param>
        public void FrameToSave(int index, string path)
        {
            this.CurrentDicom.FrameToSave(index, path);
        }

        public int? GetAge()
        {
            if (this.CurrentDicom == null || CurrentDicom.DicomFile == null) return null;
            try
            {
                CurrentDicom.DicomFile.Dataset.TryGetSingleValue<int>(DicomTag.PatientAge, out int age);
                return age > 0 ? age : null;
            }
            catch { return null; }
        }

        #endregion 加载图片

        ~DicomViewModel()
        {
            Playing = false;
        }

        #endregion 方法
    }
}